﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DSS_XNA.Engine.Error;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace DSS_XNA.Engine.Menu.Windows
{
    public class MainMenuWindow : IMenu
    {
        #region Properties

        public Game1 Engine
        {
            get { return _engine; }
        }
        private Game1 _engine = null;

        public MenuOptionCollection Options
        {
            get { return _options; }
            set { _options = value; }
        }
        private MenuOptionCollection _options = new MenuOptionCollection();

        public KeyboardState? PrevKeyboardState
        {
            get { return _prevKeyboardState; }
            set { _prevKeyboardState = value; }
        }
        KeyboardState? _prevKeyboardState = null;

        public double SelectedTextInteropTime
        {
            get { return _selectedTextInteropTime; }
            set { _selectedTextInteropTime = value; }
        }
        private double _selectedTextInteropTime = 0.0d;

        public bool SelectedTextDirection
        {
            get { return _selectedTextDirection; }
            set { _selectedTextDirection = value; }
        }
        private bool _selectedTextDirection = true; // start going up :)

        #endregion

        #region IMenu Members

        public void Render(SpriteBatch spriteBatch)
        {
            if (spriteBatch == null)
                throw new DSSException("'spriteBatch' is null.");

            Vector2 centerScreen = new Vector2();
            centerScreen.X = this.Engine.GraphicsDevice.ScissorRectangle.Width / 2; // is this the correct object to use to get the window width/height??
            centerScreen.Y = this.Engine.GraphicsDevice.ScissorRectangle.Height / 2;

            int optionHeight = 60;
            int optionWidth = 400; // this really should depend on what the text in the options is
            int optionBorderSize = 2;

            int totalOptionHeight = optionHeight + (optionBorderSize * 2);
            int totalOptionWidth = optionWidth + (optionBorderSize * 2);

            int totalOptionsHeight = this.Options.Count * totalOptionHeight;

            Vector2 startRender = new Vector2();
            startRender.X = centerScreen.X - (totalOptionWidth / 2);
            startRender.Y = centerScreen.Y - (totalOptionsHeight / 2);

            Vector2 currentPos = startRender;
            foreach (MenuOption option in this.Options)
            {
                this.RenderMenuOption(spriteBatch, option, currentPos);

                currentPos += new Vector2(0, optionHeight);
            }
        }

        public void Run(GameTime gameTime, KeyboardState ks, MouseState ms, GamePadState gs)
        {
            if (gameTime == null)
                throw new DSSException("'gameTime' is null.");

            int selectedIdx = 0;
            int oldSelectedIdx = 0;
            bool keyPressed = false;

            foreach (MenuOption option in this.Options)
            {
                if (option.IsSelected)
                {
                    selectedIdx = this.Options.IndexOf(option);
                    oldSelectedIdx = selectedIdx;
                }
            }

            if (ks.IsKeyDown(Keys.Enter))
            {
                this.Options[selectedIdx].RunAction();
                return;
            }

            if (this.PrevKeyboardState != null && this.PrevKeyboardState.Value.IsKeyUp(Keys.Down))
            {
                if (ks.IsKeyDown(Keys.Down))
                {
                    keyPressed = true;

                    selectedIdx++;
                    if (selectedIdx > this.Options.Count - 1)
                        selectedIdx = 0;
                }
            }

            if (this.PrevKeyboardState != null && this.PrevKeyboardState.Value.IsKeyUp(Keys.Up))
            {
                if (ks.IsKeyDown(Keys.Up))
                {
                    keyPressed = true;

                    selectedIdx--;
                    if (selectedIdx < 0)
                        selectedIdx = this.Options.Count - 1;
                }
            }

            if (keyPressed)
            {
                this.Options[selectedIdx].IsSelected = true;
                this.Options[oldSelectedIdx].IsSelected = false;
            }

            this.PrevKeyboardState = ks;

            this.UpdateSelectedTextFlash(gameTime);
        }

        private void UpdateSelectedTextFlash(GameTime gameTime)
        {
            if (this.SelectedTextDirection)
            {
                this.SelectedTextInteropTime += gameTime.ElapsedGameTime.Milliseconds / 1000.0d; // 1 seconds
                if (this.SelectedTextInteropTime >= 1.0d)
                    SelectedTextDirection = false;
            }
            else
            {
                this.SelectedTextInteropTime -= gameTime.ElapsedGameTime.Milliseconds / 1000.0d;
                if (this.SelectedTextInteropTime <= 0.0d)
                    SelectedTextDirection = true;
            }
        }

        #endregion

        #region Public Methods

        public MainMenuWindow(Game1 engine, MenuOptionCollection options)
        {
            if (engine == null)
                throw new DSSException("'engine' is null.");
            if (options == null)
                throw new DSSException("'options' is null.");

            this._engine = engine;
            this._options = options;
        }

        #endregion

        #region Private Methods

        private void RenderMenuOption(SpriteBatch sb, MenuOption option, Vector2 pos)
        {
            Color color = Color.Red;

            if (option.IsSelected)
            {
                color = Color.Lerp(Color.Red, Color.Yellow, (float)this.SelectedTextInteropTime);
            }
            else
            {
                color = Color.LightGray;
            }

            sb.DrawString(this.Engine.GameFont, option.Text, pos, color);
        }

        #endregion
    }
}
